/**
 * Implemententation of Min Max Algoritmn
 * @author jenc, Jeppe
 *
 * TODO:
 * add alpha, beta implementation (DONE)
 */
public class MinMaxAlg 
{	
	private int player1 = Common.PLAYER1;
	private int player2 = Common.PLAYER2;
	private int action = 0;
	private int alpha = Common.FSMALL;
	private int beta = Common.FSMALL;	
	/**
	 * @param s
	 * @return
	 */
	public int start(State s, int playerID)
	{
		Common.debug("Computer Player="+playerID);
		// Change perspective, if computer player is player1 or player2;
		if(playerID==Common.PLAYER2)
		{
			player1 = Common.PLAYER2;
			player2 = Common.PLAYER1;			
		}
		/*
		 * 
		 */
		action = s.endMoveMissingDiagonal(playerID);
		if(action != Common.NOVALUE)
		{
			Common.debug("Missing Diagonal HAS BEEN FOUND !!!!! "+action);
			return action;
		}
		/*
		 * 
		 */
		action = s.endMoveMissingHorizontal(playerID);
		if(action != Common.NOVALUE)
		{
			Common.debug("Missing ENDMOVE HAS BEEN FOUND !!!!! "+action);
			return action;
		}
		/*
		 * Killer endmoves, if we have 3 connected for a specific player
		 * we check if there 
		 */

		/*
		 * Vertical endmove, is there 3 connected where we can end this ?
		 */		
		action = s.endMovePositionVertical(playerID);
		if(action != Common.NOVALUE)
		{
			Common.debug("VERTICAL ENDMOVE HAS BEEN FOUND !!!!! "+action);
			return action;				
		}
		/*
		 * Horizontal endmove, is there 3 connected where we can end this ?
		 */
		action = s.endMovePositionHorizontal(playerID);
		if(action != Common.NOVALUE)
		{
			Common.debug("HORIZONTAL ENDMOVE HAS BEEN FOUND !!!!! "+action);
			return action;				
		}
		/*
		 * 
		 */
		action = s.endMovePositionDiagonal(playerID);
		if(action != Common.NOVALUE)
		{
			Common.debug("DIAGONAL ENDMOVE HAS BEEN FOUND !!!!! "+action);
			return action;
		}
		/*
		 * If we cannot see a clear possibility for an endmove, then we continue to
		 * use MaxMin Alg to find a suitable move
		 */
		action = 0;
		min(s, Common.DEPTH, alpha, beta);
		return action;
	}	
	/**
	 * Implements recursive min call
	 */
	public int min(State s, int depth, int alpha, int beta)
	{	
		// return the utility, if the max depth has been reached
		if(depth==0) return s.utility();
		// set v til inf. large (almost)
		int v = Common.FLARGE;
		// call new recursive
		int oldValue = Common.FLARGE;
		// call x number of recursive call, based on the possible number of
		// actions
		for(int actions=0; actions<Common.XSIZE; actions++)
		{
			// copy state to next recursive call
			State childState = s.copyBoard();
			// Determine if the column has move space left
			// then we have a legal action
			if(s.spaceLeftY[actions]<(Common.YSIZE-1))
				// if so, then we can call a rec function.
				childState.insertElement(actions, player2);

			v = this.max(childState, depth-1, alpha, beta);
			//action = actions;
			if(v < oldValue)
			{
				// save the best action and value for max
				// but if we get an action that is not legal, then
				// we ignore it, and take the next best.
				if(s.spaceLeftY[actions]<Common.YSIZE-1)
				{
					oldValue = v;
					action = actions;
				}
			}
			// test if we can do a cut here
			if(v <= alpha) return v;
			beta = Math.max(beta, v);
		}
		// return result
		return v;
	}
	/**
	 * Implements recursive max call
	 */
	public int max(State s, int depth, int alpha, int beta)
	{
		// return the utility, if the max depth has been reached
		if(depth==0) s.utility();
		// set v til inf. small (almost)
		int v = Common.FSMALL;	

		int oldValue = Common.FSMALL;
		// call x number of recursive call, based on the possible number of
		// actions
		for(int actions=0; actions<Common.XSIZE; actions++)
		{
			// copy state to next recursive call
			State childState = s.copyBoard();
			// Determine if the column has move space left
			// then we have a legal action
			if(s.spaceLeftY[actions]<(Common.YSIZE-1))			
				childState.insertElement(actions, player1);

			// make a call to next recusive state
			v = this.min(childState, depth-1, alpha, beta);

			if(v > oldValue)
			{
				// save the best action and value for max
				// but if we get an action that is not legal, then
				// we ignore it, and take the next best.
				if(s.spaceLeftY[actions]<Common.YSIZE-1)
				{
					oldValue = v;
					action = actions;
				}
			}
			// test if we can do a cut here
			if(v >= beta) return v;
			alpha = Math.max(alpha, v);
		}
		// return result
		return v;	
	}	
	/**
	 * End of class
	 */
}
